/**
 * @file delay.c
 * @brief 基于DWT的延时函数实现
 * @author 废话文学创始人
 * @version 1.0
 * @date 2024-07-14
 */

#include <delay.h>

#define us (HAL_RCC_GetSysClockFreq() / 1000000)

// #define DWT_INIT

/**
 * @brief DWT使能，并开始计数
 * @note 使用由DWT产生的延时函数前需要调用此函数进行硬件初始化
 */
void HAL_DWT_init(void)
{
	// 使能DWT
	CoreDebug->DEMCR = (CoreDebug->DEMCR) | CoreDebug_DEMCR_TRCENA_Msk;
	// 清空CYC计数寄存器的值
	DWT->CYCCNT = (uint32_t)0u;
	// 启用CYC计时器
	DWT->CTRL = (DWT->CTRL) | DWT_CTRL_CYCCNTENA_Msk;
}

/**
 * @brief 使用DWT的阻塞us级延时
 * @param nus 延时时间（微秒），有效值：1~(2^32/us)
 * @note 误差约为+1us
 */
void HAL_DWT_Delay_us(uint32_t nus)
{
	// 初始值记录
	uint32_t count_start = DWT->CYCCNT;
	// 计数次数计算
	uint32_t count_nus = nus * us;
	// 目标计数值
	uint32_t count_end = count_start + count_nus;
	// 计数到目标值
	if (count_end > count_start)
	{
		while (DWT->CYCCNT < count_end)
			;
	}
	else
	{
		while (DWT->CYCCNT > count_end)
			;
		while (DWT->CYCCNT < count_end)
			;
	}
}

/**
 * @brief 使用DWT的阻塞ms级延时
 * @param nms 延时时间（毫秒），有效值：1~2^32
 */
void HAL_DWT_Delay_ms(uint32_t nms)
{
	for (int i = 0; i < nms; i++)
	{
		HAL_DWT_Delay_us(1000);
	}
}

/**
 * @brief 纳秒级延时（精度受限于系统主频）
 * @param nns 延时时间（纳秒）
 */
void delay_ns(uint32_t nns)
{
#ifdef DWT_INIT
	HAL_DWT_Delay_us(nns);
#else
	assert_param(0);
#endif
}

/**
 * @brief 毫秒级延时
 * @param nms 延时时间（毫秒）
 */
void delay_ms(uint32_t nms)
{
#ifdef DWT_INIT
	HAL_DWT_Delay_ms(nms);
#else
	HAL_Delay(nms);
#endif
}
